﻿'XBMC4LCDSmartie
'#################################
'Plugin for LCDSmartie that displays information from XBMC
'
'(c) Oliver Tomkins

Imports System.Net
Imports System.IO
Imports System.Text
Imports Newtonsoft.Json.Linq
Imports Newtonsoft.Json
Imports System.Net.Sockets

'
Public Class LCDSmartie

    'Parameters from config section
    Public sHost As String = System.Configuration.ConfigurationManager.AppSettings("XBMC4LCDSmartie.Host")
    Public iPort As Int32 = System.Configuration.ConfigurationManager.AppSettings("XBMC4LCDSmartie.Port")
    Public sUser As String = System.Configuration.ConfigurationManager.AppSettings("XBMC4LCDSmartie.User")
    Public sPass As String = System.Configuration.ConfigurationManager.AppSettings("XBMC4LCDSmartie.Pass")
    Public iRefreshInt As Int32 = System.Configuration.ConfigurationManager.AppSettings("XBMC4LCDSmartie.RefreshInt")

    Public iId As Integer = 0


    'This funktion return if XBMC is running or not
    'Returns 1 if XBMC.exe process is found and 0 if not
    '
    Public Function function1(ByVal param1 As String, ByVal param2 As String) As String

        Return XBMCRunning()

    End Function

    'This function return different completely ready lines back to LCDSmartie
    '#########################################################################
    'param1:
    '1 - Get Player Type
    '2 - Top Line (Name, Artist, Album, Track, ...
    '3 - Time Display
    '
    'param2:
    '1 - Formats the time short as possible. Ex.: 02:34/03:41, 0:55:44/1:23:44
    '2 - Time Display without leading zero. Ex.: 00:02:34/00:03:41, 00:55:44/01:23:44
    '
    Public Function function2(ByVal param1 As String, ByVal param2 As String) As String

        If XBMCRunning() = "0" Then

            Return "XBMC Not Running"

        End If

        Return XBMCGetPlayerProperty(param1, FormatNumber(param2))

    End Function

    'This function returns the value of a InfoLabel from XBMC
    '
    Public Function function3(ByVal param1 As String, ByVal param2 As String) As String

        If XBMCRunning() = "0" Then

            Return "XBMC Not Running"

        End If

        Return XBMCGetInfoLabel(param1).ToString


    End Function

    'This function returns the current status of xbmc
    '-999 => XBMC ist not running
    '-888 => XBMC is running, but no player is started
    '-777 => XBMC is paused
    ' XXX => Current Playback speed
    '
    Public Function function4(ByVal param1 As String, ByVal param2 As String) As String

        If XBMCRunning() = "0" Then

            Return "-999"

        End If

        Return XBMCGetStatus()


    End Function

    '
    Public Function GetMinRefreshInterval() As Integer

        Return iRefreshInt

    End Function

    Function XBMCJSONReadOld2(ByVal sCommand As String)

        Dim jObject As JObject
        Dim sServerPath = "http://" & sHost & ":" & iPort & "/jsonrpc"

        Dim wc = New WebClient
        wc.Headers("Contect-Type") = "application/json"
        wc.Encoding = Encoding.UTF8

        If sUser <> "" Then
            wc.Credentials = New NetworkCredential(sUser, sPass)
        End If

        'Console.WriteLine(Date.Now.ToString("hh:mm:ss.fff"))

        jObject = jObject.Parse(wc.UploadString(sServerPath, sCommand))

        'Console.WriteLine(Date.Now.ToString("hh:mm:ss.fff"))

        If iId < 255 Then
            iId = iId + 1
        Else
            iId = 0
        End If

        Return jObject

    End Function

    Function XBMCJSONRead(ByVal sCommand As String)

        Dim jObject As New JObject
        'Dim sServerPath = "http://" & sHost & ":" & iPort & "/jsonrpc"

        'Dim wc = New WebClient
        'wc.Headers("Contect-Type") = "application/json"
        'wc.Encoding = Encoding.UTF8

        'If sUser <> "" Then
        'wc.Credentials = New NetworkCredential(sUser, sPass)
        'End If

        'Console.WriteLine(Date.Now.ToString("hh:mm:ss.fff"))

        'jObject = jObject.Parse(wc.UploadString(sServerPath, sCommand))

        'Console.WriteLine(Date.Now.ToString("hh:mm:ss.fff"))

        'Try
        ' Create a TcpClient.
        ' Note, for this client to work you need to have a TcpServer 
        ' connected to the same address as specified by the server, port
        ' combination.

        'MsgBox("Read")

        Dim client As New TcpClient(sHost, iPort)

        ' Translate the passed message into ASCII and store it as a Byte array.
        Dim data As [Byte]() = System.Text.Encoding.UTF8.GetBytes(sCommand)

        ' Get a client stream for reading and writing.
        '  Stream stream = client.GetStream();
        Dim stream As NetworkStream = client.GetStream()

        ' Send the message to the connected TcpServer. 
        stream.Write(data, 0, data.Length)

        'Console.WriteLine("Sent: {0}", message)

        ' Receive the TcpServer.response.
        ' Buffer to store the response bytes.
        data = New [Byte](1024) {}

        ' String to store the response ASCII representation.
        Dim responseData As [String] = [String].Empty

        ' Read the first batch of the TcpServer response bytes.
        Dim bytes As Int32 = stream.Read(data, 0, data.Length)

        jObject = jObject.Parse(System.Text.Encoding.UTF8.GetString(data, 0, bytes))
        'Console.WriteLine(jObject.ToString)

        ' Close everything.
        stream.Close()
        client.Close()

        'Catch e As ArgumentNullException
        'Console.WriteLine("ArgumentNullException: {0}", e)

        'Catch e As SocketException
        'Console.WriteLine("SocketException: {0}", e)

        'End Try

        If iId < 255 Then
            iId = iId + 1
        Else
            iId = 0
        End If

        'MsgBox("ReadFinished")

        Return jObject

    End Function

    Function XBMCJSONReadOld(ByVal sCommand As String)

        'Set up URL
        Dim sServerPath = "http://" & sHost & ":" & iPort & "/jsonrpc"
        Dim webReqest As HttpWebRequest = WebRequest.Create(sServerPath)
        Dim strStream As System.IO.Stream
        Dim strStreamReader As StreamReader
        Dim byteArray = Encoding.ASCII.GetBytes(sCommand)
        Dim jObj As JObject
        Dim sResponse As String

        'Console.WriteLine(Date.Now.ToString("hh:mm:ss.fff"))

        webReqest.Method = "POST"
        webReqest.ContentLength = sCommand.Length
        webReqest.ContentType = "application/x-www-form-urlencoded"

        'Only use user & pass if user is specified in config file
        If sUser <> "" Then
            webReqest.Credentials = New NetworkCredential(sUser, sPass)
        End If

        strStream = webReqest.GetRequestStream
        strStream.Write(byteArray, 0, byteArray.Length)
        strStream.Close()

        'Read response and make JSON-Object
        strStreamReader = New StreamReader(webReqest.GetResponse.GetResponseStream)
        sResponse = strStreamReader.ReadToEnd
        jObj = JObject.Parse(sResponse)

        'Console.WriteLine(Date.Now.ToString("hh:mm:ss.fff"))

        'Console.WriteLine(jObj.ToString())

        Return jObj

    End Function

    Function XBMCGetInfoLabel(ByVal sInfoLabel As String)

        Dim sw As New StringWriter
        Dim test As New JsonTextWriter(sw)
        Dim jResponse As JObject

        test.Formatting = Formatting.Indented

        test.WriteStartObject()
        test.WritePropertyName("jsonrpc")
        test.WriteValue("2.0")
        test.WritePropertyName("id")
        test.WriteValue(iId.ToString)

        test.WritePropertyName("method")
        test.WriteValue("XBMC.GetInfoLabels")

        test.WritePropertyName("params")
        test.WriteStartObject()
        test.WritePropertyName("labels")
        test.WriteStartArray()
        test.WriteValue(sInfoLabel)
        test.WriteEndArray()
        test.WriteEndObject()
        test.WriteEndObject()

        'Console.WriteLine(sw.ToString)

        jResponse = XBMCJSONRead(sw.ToString)

        Return RemoveSpecialChars(jResponse.SelectToken("result").First.First)

    End Function

    Function RemoveSpecialChars(ByVal sString As String)

        'Replace Special Chars that cannot be displayed correctly
        Dim sArray(5, 1) As String

        sArray(0, 0) = "ö" : sArray(0, 1) = "oe"
        sArray(1, 0) = "ü" : sArray(1, 1) = "ue"
        sArray(2, 0) = "ä" : sArray(2, 1) = "ae"
        sArray(3, 0) = "ß" : sArray(3, 1) = "ss"
        sArray(4, 0) = "[" : sArray(3, 1) = "("
        sArray(5, 0) = "]" : sArray(3, 1) = ")"

        For i = 0 To (sArray.Length / 2) - 1
            sString = sString.Replace(sArray(i, 0), sArray(i, 1))
        Next

        Return sString

    End Function

    Function XBMCGetActivePlayer()

        Dim sw As New StringWriter
        Dim test As New JsonTextWriter(sw)
        Dim jResponse As JObject

        test.Formatting = Formatting.Indented

        test.WriteStartObject()
        test.WritePropertyName("jsonrpc")
        test.WriteValue("2.0")
        test.WritePropertyName("id")
        test.WriteValue(iId.ToString)
        test.WritePropertyName("method")
        test.WriteValue("Player.GetActivePlayers")
        test.WriteEndObject()

        'Console.WriteLine(sw.ToString)

        jResponse = XBMCJSONRead(sw.ToString)

        'Console.WriteLine(jResponse.ToString)

        If IsNothing(jResponse("result").First) Then

            Return -1

        End If
        'Console.WriteLine(jResponse("result"))

        'Console.WriteLine(jResponse("result").Item(0).SelectToken("playerid"))

        Return (jResponse("result").First.SelectToken("playerid").ToString)

    End Function

    Function XBMCGetPlayerProperty(ByVal sProperty As String, ByVal iFormat As Integer)

        Dim sw As New StringWriter
        Dim test As New JsonTextWriter(sw)
        Dim jResponse As JObject
        Dim iPlayer As Integer
        Dim sText As String
        Dim iTrack As Integer
        Dim sValues As New List(Of String)

        Select Case sProperty
            Case "3"

                iPlayer = XBMCGetActivePlayer()

                If iPlayer = -1 Then
                    Return "No Active Player!"
                End If

                sValues.Add("time")
                sValues.Add("totaltime")

                'Console.WriteLine(sw.ToString)
                jResponse = GetPlayerProperties(iPlayer, sValues.ToArray)

                'Console.WriteLine(jResponse.ToString)

                Dim Time As DateTime = jResponse.SelectToken("time.hours").ToString & ":" & jResponse.SelectToken("time.minutes").ToString & ":" & jResponse.SelectToken("time.seconds").ToString
                Dim TotalTime As DateTime = jResponse.SelectToken("totaltime.hours").ToString & ":" & jResponse.SelectToken("totaltime.minutes").ToString & ":" & jResponse.SelectToken("totaltime.seconds").ToString

                Select Case iFormat
                    Case 1
                        'iMon-Displaystring
                        If TotalTime.Hour > 0 Then
                            'Return (Time.Hour * 60 + Time.Minute).ToString("0") & ":" & Time.Second.ToString("00") & "/" & (TotalTime.Hour * 60 + TotalTime.Minute).ToString("0") & ":" & TotalTime.Second.ToString("00")
                            Return Time.ToString("H:mm:ss") & "/" & TotalTime.ToString("H:mm:ss")
                            'Return Time.Hour.ToString("0") & ":" & Time.Minute.ToString("00") & ":" & Time.Second.ToString("00") & "/" & (TotalTime.Hour * 60 + TotalTime.Minute).ToString("0") & ":" & TotalTime.Second.ToString("00")
                        Else
                            'Return Time.Minute.ToString("0") & ":" & Time.Second.ToString("00") & "/" & TotalTime.Minute.ToString("0") & ":" & TotalTime.Second.ToString("00")
                            Return Time.ToString("m:ss") & "/" & TotalTime.ToString("m:ss")
                        End If
                    Case Else
                        Return Time.ToLongTimeString & "/" & TotalTime.ToLongTimeString
                End Select

            Case "1"

                iPlayer = XBMCGetActivePlayer()

                If iPlayer < 0 Then

                    Return "No Active Player!"

                Else

                    jResponse = GetPlayerItems(iPlayer, sValues.ToArray)

                    Return jResponse.SelectToken("item.type")

                End If

            Case "2" 'Display Top-Line

                iPlayer = XBMCGetActivePlayer()

                If iPlayer < 0 Then

                    Return "No Active Player!"

                Else

                    sValues.Add("season")
                    sValues.Add("episode")
                    sValues.Add("title")
                    sValues.Add("showtitle")
                    sValues.Add("year")
                    sValues.Add("artist")
                    sValues.Add("albumartist")
                    sValues.Add("track")

                    jResponse = GetPlayerItems(iPlayer, sValues.ToArray)

                    Select Case jResponse.SelectToken("item.type")

                        Case "episode"

                            'Console.WriteLine(jResponse.SelectToken("item.season").ToString("0") & "x" & _
                            '                  jResponse.SelectToken("item.episode").ToString("0") & " " & _
                            '                  jResponse.SelectToken("item.title").ToString & " (" & _
                            '                  jResponse.SelectToken("item.showtitle").ToString & ")")

                            Return jResponse.SelectToken("item.season").ToString("0") & "x" & _
                                   jResponse.SelectToken("item.episode").ToString("0") & " " & _
                                   jResponse.SelectToken("item.title").ToString & " (" & _
                                   jResponse.SelectToken("item.showtitle").ToString & ")"

                        Case "movie"

                            If FormatNumber(jResponse.SelectToken("item.year").ToString) < 1 Then

                                sText = jResponse.SelectToken("item.title").ToString

                            Else

                                sText = jResponse.SelectToken("item.title").ToString & " (" & _
                                        jResponse.SelectToken("item.year").ToString & ")"

                            End If

                            'Console.WriteLine(sText)

                            Return sText

                        Case "song"

                            'Compilation is beeing played
                            If jResponse.SelectToken("item.artist").ToString IsNot jResponse.SelectToken("item.albumartist").ToString Then

                                iTrack = jResponse.SelectToken("item.track")

                                sText = iTrack.ToString("D2") & "." & _
                                    jResponse.SelectToken("item.title").ToString & " (" & _
                                        jResponse.SelectToken("item.artist").ToString & ")"

                            Else

                                sText = iTrack.ToString("D2") & "." & _
                                    jResponse.SelectToken("item.title").ToString

                            End If

                            'Console.WriteLine(sText)

                            Return sText

                        Case Else

                            Return "NoValidParameters!"

                    End Select

                End If

            Case Else

                Return "Error! Please enter a correct param1!"

        End Select

    End Function

    Function XBMCRunning()

        For Each clsProcess As Process In Process.GetProcesses()
            If clsProcess.ProcessName.StartsWith("XBMC") Then
                Return "1"
            End If
        Next

        Return "0"

    End Function

    Function GetPlayerItems(ByVal iPlayerID As Integer, ByVal sValues As Array)

        Dim sw As New StringWriter
        Dim test As New JsonTextWriter(sw)
        Dim jResponse As JObject

        test.Formatting = Formatting.Indented

        test.WriteStartObject()
        test.WritePropertyName("jsonrpc")
        test.WriteValue("2.0")
        test.WritePropertyName("id")
        test.WriteValue(iId.ToString)
        test.WritePropertyName("method")
        test.WriteValue("Player.GetItem")
        test.WritePropertyName("params")
        test.WriteStartObject()
        test.WritePropertyName("playerid")
        test.WriteValue(iPlayerID)
        test.WritePropertyName("properties")
        test.WriteStartArray()

        For Each sValue In sValues

            test.WriteValue(sValue.ToString)

        Next

        'test.WriteValue("title")
        'test.WriteValue("episode")
        'test.WriteValue("showtitle")
        'test.WriteValue("season")
        'test.WriteValue("year")
        'test.WriteValue("originaltitle")
        'test.WriteValue("artist")
        'test.WriteValue("albumartist")
        'test.WriteValue("track")
        'test.WriteValue("album")
        'test.WriteValue("set")

        test.WriteEndArray()
        test.WriteEndObject()
        test.WriteEndObject()
        'Console.WriteLine(sw.ToString)
        jResponse = XBMCJSONRead(sw.ToString)
        'Console.WriteLine(jResponse.ToString)
        Return jResponse("result")

    End Function

    Function GetPlayerProperties(ByVal iPlayerID As Integer, ByVal sValues As Array)

        Dim sw As New StringWriter
        Dim test As New JsonTextWriter(sw)
        Dim jResponse As JObject

        test.Formatting = Formatting.Indented

        test.WriteStartObject()
        test.WritePropertyName("jsonrpc")
        test.WriteValue("2.0")
        test.WritePropertyName("id")
        test.WriteValue(iId.ToString)
        test.WritePropertyName("method")
        test.WriteValue("Player.GetProperties")
        test.WritePropertyName("params")
        test.WriteStartObject()
        test.WritePropertyName("playerid")
        test.WriteValue(iPlayerID)
        test.WritePropertyName("properties")

        test.WriteStartArray()

        For Each sValue In sValues

            test.WriteValue(sValue.ToString)

        Next

        'test.WriteValue("percentage")
        'test.WriteValue("totaltime")
        'test.WriteValue("time")
        'test.WriteValue("speed")
        'test.WriteValue("currentaudiostream")
        'test.WriteValue("canrotate")
        'test.WriteValue("canrepeat")
        'test.WriteValue("canshuffle")
        'test.WriteValue("shuffled")
        'test.WriteValue("canmove")
        'test.WriteValue("subtitleenabled")
        'test.WriteValue("type")
        'test.WriteValue("repeat")
        'test.WriteValue("canseek")
        'test.WriteValue("currentsubtitle")
        'test.WriteValue("subtitles")
        'test.WriteValue("canzoom")
        'test.WriteValue("playlistid")
        'test.WriteValue("audiostreams")
        'test.WriteValue("partymode")
        'test.WriteValue("position")
        'test.WriteValue("canchangespeed")

        test.WriteEndArray()

        test.WriteEndObject()
        test.WriteEndObject()

        'Console.WriteLine(sw.ToString)
        jResponse = XBMCJSONRead(sw.ToString)
        'Console.WriteLine(jResponse.ToString)

        Return jResponse("result")

    End Function

    Function XBMCGetStatus()

        Dim sValues As New List(Of String)
        Dim iPlayer As Integer
        Dim jResponse As JObject

        iPlayer = XBMCGetActivePlayer()

        If iPlayer = -1 Then
            Return "-888"
        End If

        sValues.Add("speed")

        'Console.WriteLine(sw.ToString)
        jResponse = GetPlayerProperties(iPlayer, sValues.ToArray)

        'Console.WriteLine(jResponse.ToString)

        If jResponse.SelectToken("speed").ToString = "0" Then
            Return "-777"
        End If

        Return jResponse.SelectToken("speed").ToString

    End Function


End Class

